package jt.classic.system.workflow;

import jt.classic.system.ISystem;
import jt.classic.system.SimpleManager;
import jt.classic.system.group.GroupJsonBean;
import jt.classic.system.group.GroupJsonBean4Chk;
import jt.classic.system.group.GroupManager;
import jt.classic.system.group.IGroup;
import jt.classic.system.role.IRole;
import jt.classic.system.role.RoleManager;
import jt.classic.system.user.IUser;
import jt.classic.system.user.UserManager;
import jt.classic.system.utils.AnnexTool;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;

import org.limp.basework.Column;
import org.limp.basework.ColumnNotFoundException;
import org.limp.basework.ProcessorException;
import org.limp.basework.SimpleBean;
import org.limp.basework.SimpleBean4Table;
import org.limp.basework.SimpleBeanProcessor;
import org.limp.basework.Table;
import org.limp.basework.analyzer.SimpleBeanAnalyzer;
import org.limp.basework.analyzer.SimpleBeanAnalyzerWrap;
import org.limp.basework.analyzer.TableRegisterCenter;
import org.limp.basework.console.XSystemConfig;
import org.limp.basework.impl.CommonBean4HSQ;
import org.limp.basework.impl.SimpleBean4TableImpl;
import org.limp.basework.impl.SimpleBeanImpl;
import org.limp.basework.processor.SingleBeanProcessor;
import org.limp.basework.tools.BaseworkUtil;
import org.limp.basework.tools.SimpleBeanTransform;

import org.limp.mine.DataTrimmerI;
import org.limp.mine.DataTrimmerI.DataItemList;
import org.limp.mine.DateTrimmer;
import org.limp.mine.RandomUtil;
import org.limp.mine.StringTool;
import org.limp.mine.annex.AnnexInfo;
import org.limp.mine.annex.AnnexItem;
import org.limp.mine.annex.transactor.AnnexTransactorException;

import java.sql.Connection;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;


/**
 * 工作流转引擎类
 *
 * @author bizkit
 *
 */
public final class WorkflowEngine extends SimpleManager {
    private String context = (String) XSystemConfig.config().getProperty(XSystemConfig.XSYSTEM_CONTEXT);
    private String eventservice = (String) XSystemConfig.config().getProperty("XSYSTEM_WORKSTATION_EVENTSERVICE");
    private String service = (String) XSystemConfig.config().getProperty("XSYSTEM_WORKSTATION_SERVICE");
    private String encoding = (String) XSystemConfig.config().getProperty(XSystemConfig.XSYSTEM_CHARSETNAME);
    private String schema;
    private String serverName;
    private int serverPort;

    public WorkflowEngine() {
        super();
    }

    public WorkflowEngine(Connection conn) {
        super(conn);
    }

    /**
     * 环节办理权限
     * @param obj
     * @param user
     * @return
     */
    public void right4handle(WStep step, IUser user) throws WorkflowException {
        boolean rnt = (step.irangetype() == 1) &&
            ISystem.matchrole(user, step.irangeids());

        if (!rnt) {
            throw new WorkflowException("no right to handle step['" +
                step.iname() + "'] of flow['" + step.iflow().iname() + "'].");
        }
    }

    /**
     * 获取流转实例文号(numberType,numberValue,numberPrefix)
     *
     * @param sequence 流转实例唯一标识
     * @size 文号长度
     *
     * @return String
     */
    public String getInstanceNumber(String sequence, int size) {
        String sql = "SELECT * FROM WF_NUMBER WHERE INS_SEQUENCE = ? AND ONUSE = 1";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();
        dil.set(sequence);

        Map myinfo = this.trimmerI.searchSingleData(sql, dil);

        String result = "";

        if (myinfo != null) {
            String numberType = (String) myinfo.get("PKID");
            result += (numberType + ",");

            String num = (String) myinfo.get("NUM_VALUE");

            int s = size - num.length();

            for (int i = 0; i < s; i++) {
                result += "0";
            }

            result += num;

            String prefix = (String) myinfo.get("NUM_PREFIX");

            result += ("," + prefix);
        }

        return result;
    }

    /**
     * 自动生成编号
     * @param sequence 实例ID
     * @param numberid 编号类型
     * @param prefix 文号前缀
     * @param suffix 文号后缀
     * @param size 流水号尺寸
     * @throws WorkflowException
     * @return String
     */
    public String getnumber(String sequence, String numberid, String prefix,
        String suffix, int size) throws WorkflowException {
        String result = "";

        String sql = "SELECT * FROM WF_NUMBER WHERE INS_SEQUENCE = ? AND PKID = ? AND NUM_PREFIX = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();
        dil.set(sequence);
        dil.set(numberid);
        dil.set(prefix);

        Map myinfo = this.trimmerI.searchSingleData(sql, dil);

        /*实例存在编号,获取编号*/
        if (myinfo != null) {
            String num = (String) myinfo.get("NUM_VALUE");

            sql = "UPDATE WF_NUMBER SET ONUSE = 1 WHERE INS_SEQUENCE = ? AND PKID = ? AND NUM_PREFIX = ?";

            DataTrimmerI.DataItemList dil1 = this.trimmerI.createDIL();
            dil1.set(sequence);
            dil1.set(numberid);
            dil1.set(prefix);

            if (!this.trimmerI.execute(sql, dil1)) {
                throw new WorkflowException("get new number error.");
            }

            int s = size - num.length();

            for (int i = 0; i < s; i++) {
                result += "0";
            }

            result += num;

            return result;
        } else {
            /*不存在编号,新分配编号*/
            /*空闲的编号*/
            sql = "SELECT * FROM WF_NUMBER WHERE NUM_VALUE = (SELECT MIN(NUM_VALUE) FROM WF_NUMBER WHERE PKID = ? AND NUM_PREFIX = ? AND ONUSE = 0)";

            DataTrimmerI.DataItemList dil1 = this.trimmerI.createDIL();
            dil1.set(numberid);
            dil1.set(prefix);

            Map info = this.trimmerI.searchSingleData(sql, dil1);

            if (info != null) {
                String num = (String) info.get("NUM_VALUE");

                int s = size - num.length();

                for (int i = 0; i < s; i++) {
                    result += "0";
                }

                result += num;

                sql = "UPDATE WF_NUMBER SET INS_SEQUENCE = ? ,ONUSE = 1 WHERE NUM_VALUE = ? AND PKID = ? AND NUM_PREFIX = ?";

                DataTrimmerI.DataItemList dil2 = this.trimmerI.createDIL();
                dil2.set(sequence);
                dil2.set(num);
                dil2.set(numberid);
                dil2.set(prefix);

                if (!this.trimmerI.execute(sql, dil2)) {
                    throw new WorkflowException("lock number error.");
                }
            } else {
                /*最大编号*/
                sql = "SELECT MAX(NUM_VALUE) AS NUM_VALUE FROM WF_NUMBER WHERE PKID = ? AND NUM_PREFIX = ?";

                DataTrimmerI.DataItemList dil2 = this.trimmerI.createDIL();
                dil2.set(numberid);
                dil2.set(prefix);

                Map maxinfo = this.trimmerI.searchSingleData(sql, dil2);

                int max = 1;

                if (maxinfo != null) {
                    max = Integer.parseInt((String) maxinfo.get("NUM_VALUE"));
                    max++;
                }

                SimpleBean4Table sbt = new SimpleBean4TableImpl("WF_NUMBER");
                sbt.getResource().put("isequence", sequence);
                sbt.getResource().put("pkid", numberid);
                sbt.getResource().put("nvalue", max);
                sbt.getResource().put("nprefix", prefix);
                sbt.getResource().put("nsuffix", suffix);
                sbt.getResource().put("nonuse", "1");

                BaseworkUtil util = new BaseworkUtil();

                try {
                    util.manualSave1(sbt, conn);
                } catch (Exception ex) {
                    throw new WorkflowException("get next number error.", ex);
                }

                int s = size - String.valueOf(max).length();

                for (int i = 0; i < s; i++) {
                    result += "0";
                }

                result = result + max;
            }
        }

        return result;
    }

    /**
     * 回收编号
     * @param numberid
     * @param number
     * @param sequence
     * @throws WorkflowException
     */
    public void callbacknumber(String numberid, String number, String sequence)
        throws WorkflowException {
        String sql = "UPDATE WF_NUMBER SET ONUSE = 0 WHERE INS_SEQUENCE = ? AND NUM_VALUE = ? AND PKID = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();
        dil.set(sequence);
        dil.set(number);
        dil.set(numberid);

        if (!this.trimmerI.execute(sql, dil)) {
            throw new WorkflowException("workflowengine callback number error.");
        }
    }

    /**
     * 文号校验
     * @param numberid
     * @param prefix
     * @param number
     * @param sequence
     * @throws WorkflowException
     * @return boolean
     */
    public boolean checknumber(String numberid, String prefix, String number,
        String sequence) throws WorkflowException {
        String sql = "SELECT ONUSE FROM WF_NUMBER WHERE PKID = ? AND NUM_VALUE = ? AND NUM_PREFIX = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();
        dil.set(numberid);
        dil.set(number);
        dil.set(prefix);

        Map temp = trimmerI.searchSingleData(sql, dil);

        /*文号没有被占用*/
        boolean r = (temp != null) && "1".equals(temp.get("ONUSE"));

        return r;
    }

    /**
     * 锁定文号
     * @param request
     * @throws WorkflowException
     * @return boolean
     */
    public void locknumber(String numberid, String number, String sequence,
        String prefix, String suffix) throws WorkflowException {
        String sql = "SELECT * FROM WF_NUMBER WHERE PKID = ? AND NUM_VALUE = ? AND INS_SEQUENCE = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();
        dil.set(numberid);
        dil.set(number);
        dil.set(sequence);

        if (this.trimmerI.haveMoreData(sql, dil)) {
            String sql1 = "UPDATE WF_NUMBER SET ONUSE = 1 WHERE PKID = ? AND NUM_VALUE = ? AND INS_SEQUENCE = ?";

            DataTrimmerI.DataItemList dil1 = this.trimmerI.createDIL();
            dil1.set(numberid);
            dil1.set(number);
            dil1.set(sequence);

            if (!trimmerI.execute(sql1, dil)) {
                throw new WorkflowException("lock number error.");
            }
        } else {
            SimpleBean4Table sbt = new SimpleBean4TableImpl("WF_NUMBER");
            sbt.getResource().put("isequence", sequence);
            sbt.getResource().put("pkid", numberid);
            sbt.getResource().put("nvalue", number);
            sbt.getResource().put("nprefix", prefix);
            sbt.getResource().put("nsuffix", suffix);
            sbt.getResource().put("nonuse", "1");

            BaseworkUtil util = new BaseworkUtil();

            try {
                util.manualSave1(sbt, conn);
            } catch (Exception ex) {
                throw new WorkflowException("lock number error.");
            }
        }
    }

    /**
     * 归还文号
     * @param id 文号类别
     * @param number 文号流水号
     * @param sequence 实例序列号
     * @throws WorkflowException
     * @return boolean
     */
    public boolean repaynumber(String id, String number, String sequence)
        throws WorkflowException {
        String sql = "UPDATE WF_NUMBER SET ONUSE = 0 WHERE INS_SEQUENCE = ? AND PKID = ? AND NUM_VALUE = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

        dil.set(sequence);
        dil.set(id);
        dil.set(number);

        return this.trimmerI.execute(sql, dil);
    }

    /**
     * 保存正文
     * @param request
     * @throws WorkflowException
     * @return AnnexInfo
     */
    public AnnexInfo savedoc(HttpServletRequest request)
        throws WorkflowException {
        CommonBean4HSQ para = null;
        AnnexInfo result = null;

        try {
            para = new CommonBean4HSQ(request);

            Map info = para.getResource();

            String id = (String) info.get("sequenceA");
            String fileName = (String) info.get("columnName");
            String columnName = (String) info.get("columnName");
            String tableName = (String) info.get("tableName");

            AnnexTool tool = new AnnexTool(conn);

            if (info.containsKey(AnnexItem.ANNEX)) {
                AnnexInfo temp = tool.getAnnex(id, "WF_INSTANCE", fileName);

                if (temp != null) {
                    tool.deleteAnnex(temp.getID());
                }

                AnnexItem item = (AnnexItem) info.get(AnnexItem.ANNEX);
                item.setObjectId(id);
                item.setObjectName("WF_INSTANCE");

                tool.saveAnnex(item, fileName, true);

                result = tool.getAnnex(id, "WF_INSTANCE", fileName);
            }
        } catch (Exception ex) {
            throw new WorkflowException("workflowengine savedoc error.", ex);
        }

        return result;
    }

    /**
     * 拟稿
     * @param obj 流转对象
     * @param user 拟稿人
     * @return WFlow 流转实例
     * @throws WorkflowException
     */
    public WFlow nev(String key, IUser user) throws WorkflowException {
        WorkflowManager manager = new WorkflowManager(this.conn);

        WFlow flow = manager.getWFlowByKey(key);

        if ((flow == null) || flow.isEmpty()) {
            throw new WorkflowException("没有定义[" + key + "]工作流程,无法新建流程.");
        }

        WStep startStep = flow.istep4start();

        if (startStep == null) {
            throw new WorkflowException("没有为工作流程 [" + key + "] 定义开始环节,无法新建流程.");
        }

        this.right4handle(flow.istep4start(), user);

        return flow;
    }

    /**
     * 流转拟稿保存操作 (返回新活动记录ID)
     * @param request
     * @return String
     * @throws WorkflowException
     */
    public String save(HttpServletRequest request) throws WorkflowException {
        CommonBean4HSQ para = null;

        try {
            para = new CommonBean4HSQ(request);
        } catch (Exception ex) {
            throw new WorkflowException("workflowengine save error.", ex);
        }

        /*环节ID*/
        String sid = (String) para.getResource().get("sid");

        /*活动记录标题*/
        String atitle = (String) para.getResource().get("atitle");

        /*流程类别ID*/
        String gid = (String) para.getResource().get("gid");

        /*当前办理人IP*/
        String ip = (String) para.getResource().get("eip");

        /*当前办理人hostname*/
        String hostname = (String) para.getResource().get("ehostname");

        /*当前办理人mac*/
        String mac = (String) para.getResource().get("emac");

        /*实例序列*/
        String sequenceA = (String) para.getResource().get("insequence");

        /*流程类别*/
        String flowtype = (String) para.getResource().get("instype");

        /*起草岗位ID*/
        String postid = (String) para.getResource().get("inscpostid");

        /*流转对象key*/
        String objkey = (String) para.getResource().get("insobject");

        WorkflowManager wfmanager = new WorkflowManager(this.conn);
        WFlow flow = wfmanager.getWFlowById(gid);

        if (flow == null) {
            throw new WorkflowException("workflowengine save error,flow[" +
                gid + "]||[" + objkey + "] is null.");
        }

        WObject obj = flow.iobject();

        IUser user = ISystem.getSessionUser(request);

        String insid = this.createNewInstance(flow, user, sequenceA);

        String aid = this.createStaticActivity(insid, sid, user, atitle);

        this.createExecutor(aid, user, ip, hostname, mac);

        createFlowObject(para, obj, aid, null);

        return aid;
    }

    /**
     * 修改流转文件
     * @param request
     * @throws WorkflowException
     */
    public String update(HttpServletRequest request) throws WorkflowException {
        CommonBean4HSQ para = null;

        try {
            para = new CommonBean4HSQ(request);
        } catch (Exception ex) {
            throw new WorkflowException("workflowengine update error.", ex);
        }

        /*活动记录ID*/
        String aid = (String) para.getResource().get("aid");

        /*活动记录标题*/
        String atitle = (String) para.getResource().get("atitle");

        /*流程类别ID*/
        String gid = (String) para.getResource().get("gid");

        /*当前办理人IP*/
        String ip = (String) para.getResource().get("eip");

        /*当前办理人hostname*/
        String hostname = (String) para.getResource().get("ehostname");

        /*当前办理人mac*/
        String mac = (String) para.getResource().get("emac");

        /*流程类别*/
        String flowtype = (String) para.getResource().get("instype");

        /*起草岗位ID*/
        String postid = (String) para.getResource().get("inscpostid");

        /*流转对象key*/
        String objkey = (String) para.getResource().get("insobject");

        /*流转支持的系统*/
        String supportcenter = (String) para.getResource().get("supportcenter");

        WorkflowManager wfmanager = new WorkflowManager(this.conn);
        WFlow flow = wfmanager.getWFlowById(gid);

        if (flow == null) {
            throw new WorkflowException("workflowengine update error,flow[" +
                gid + "||" + objkey + "] is null.");
        }

        WObject obj = flow.iobject();

        IUser user = ISystem.getSessionUser(request);

        this.updateActivityTitle(aid, atitle);
        this.updateExecutor(aid, ip, hostname, mac);
        this.lockactivity(aid, user);
        this.updateFlowObject(para, obj, aid);

        return aid;
    }

    /**
     * 发送文件
     * @param request
     * @throws WorkflowException
     */
    public void send(HttpServletRequest request) throws WorkflowException {
        CommonBean4HSQ para = null;

        this.schema = request.getScheme();
        this.serverName = request.getServerName();
        this.serverPort = request.getServerPort();

        try {
            para = new CommonBean4HSQ(request);
        } catch (Exception ex) {
            throw new WorkflowException("workflowengine send error.", ex);
        }

        String aid = StringTool.checkString((String) para.getResource().get("aid"));

        if (aid.equals("0")) {
            IUser user = ISystem.getSessionUser(request);
            this.send2start(para, user);
        } else if (!aid.equals("0")) {
            this.send2run(para);
        }
    }

    /**
     * 编辑
     * @param id 活动记录ID
     * @param user 活动记录执行人
     * @throws WorkflowException
     */
    public WActivity edit(String id, IUser user) throws WorkflowException {
        WActivity activity = this.getActivityById(id);

        this.isowner(activity, user);

        return activity;
    }

    /**
     * 查看
     * @param id 活动记录ID
     * @param user 活动记录执行人
     * @throws WorkflowException
     */
    public WActivity view(String id, IUser user) throws WorkflowException {
        WActivity activity = this.getActivityById(id);

        this.isowner(activity, user);

        return activity;
    }

    /**
     * 查看传阅文件
     * @param id 活动记录ID
     * @param user 活动记录执行人
     * @throws WorkflowException
     */
    public WActivity viewencyclic(String id, IUser user)
        throws WorkflowException {
        String flumeid = user.iallgroupflumeid(",");

        String groupIds = UserManager.iallgroupflumeid(flumeid);

        String sqlwhere = " ((WF_CC.OBJ_ID = '" + user.id() +
            "' AND OBJ_TYPE = 'user') OR (WF_CC.OBJ_ID IN (" + groupIds +
            ") AND OBJ_TYPE = 'group')) ";

        String sql =
            "SELECT WF_ACTIVITY.A_ID FROM WF_ACTIVITY,WF_CC WHERE WF_ACTIVITY.A_ID = " +
            "WF_CC.A_ID AND " + sqlwhere + " AND WF_CC.A_ID = ?";

        DataItemList dil = this.trimmerI.createDIL();

        dil.set(id);

        WActivity activity = null;

        if (this.trimmerI.haveMoreData(sql, dil)) {
            activity = this.getActivityById(id);
        } else {
            throw new WorkflowException("no right to encyclic [" + id + "].");
        }

        return activity;
    }

    /**
     * 撤销
     * @param id 实例ID
     * @param user 活动记录执行人
     * @throws WorkflowException
     */
    public void cancel(String id, IUser user) throws WorkflowException {
        this.cancelinstance(id);
    }

    /**
     * 重启
     * @param id 实例ID
     * @param user 活动记录执行人
     * @throws WorkflowException
     */
    public void awake(String id, IUser user) throws WorkflowException {
        this.activateflow(id);
    }

    /**
     * 传阅查看
     * @param id 活动记录ID
     * @param user 活动记录执行人
     * @throws WorkflowException
     */
    public void encyclic(String id, IUser user) throws WorkflowException {
        WActivity activity = this.getActivityById(id);

        this.isowner(activity, user);

        this.setActivityState(activity.id(), 1);
    }

    /**
     * 取回流程活动
     * @param activity 要取回的流程活动
     * @param activity 当前流程活动
     * @param user 操作人
     * @throws WorkflowException
     */
    public String retakeactivity(WActivity activity, WActivity current,
        IUser user) throws WorkflowException {
        this.isowner(current, user);

        String newaid = null;

        if (activity.ilock()) {
            throw new WorkflowException("activity '" + activity.id() +
                "' is locked.");
        } else {
            this.setActivityState(activity.id(), -2);

            /*当前实例处在内部流转环节,主办环节取回*/
            if (activity.instance().ininner() &&
                    (activity.istep().inner() > 0) &&
                    (current.istep().inner() == 0)) {
                /*全部取回*/
                if (activity.instance().iotherinnerisok(activity.istep().inner(),
                            activity.iprocess(), activity.igroup())) {
                    WInner inner = null;
                    inner.ihandler().converge(null, activity);

                    newaid = this.createNewActivity(current.instance().id(),
                            activity.id(), current.istep().id(),
                            current.iexecutor().iuser(), current.ititle(),
                            current.iprocess(), current.igroup(), "");

                    this.createExecutor(newaid, current.iexecutor().iuser(),
                        "", "", "");

                    this.copyFlowObject(activity, newaid);
                }
            }
            /*当前实例处在主办流程,内部流转环节取回主办环节记录*/
            else if (!activity.instance().ininner() &&
                    (activity.istep().inner() == 0) &&
                    (current.istep().inner() > 0)) {
                /*内部流转最后活动记录*/
                WActivity inner4out = activity.instance().inner4out(current.istep()
                                                                           .inner(),
                        current.iprocess(), current.igroup());
                newaid = this.createNewActivity(inner4out.instance().id(),
                        activity.id(), inner4out.istep().id(),
                        inner4out.iexecutor().iuser(), inner4out.ititle(),
                        inner4out.iprocess(), inner4out.igroup(), "");

                this.createExecutor(newaid, inner4out.iexecutor().iuser(), "",
                    "", "");

                this.copyFlowObject(inner4out, newaid);
            } else {
                newaid = this.createNewActivity(current.instance().id(),
                        activity.id(), current.istep().id(),
                        current.iexecutor().iuser(), current.ititle(),
                        current.iprocess(), current.igroup(), "");

                this.createExecutor(newaid, current.iexecutor().iuser(), "",
                    "", "");

                this.copyFlowObject(activity, newaid);
            }
        }

        return newaid;
    }

    /**
     * 取回流程活动(不作身份校验)
     *
     * @param activity 要取回的流程活动
     * @param user 操作人
     * @throws WorkflowException
     */
    public String retake4sactivity(WActivity activity, IUser user)
        throws WorkflowException {
        String newaid = null;

        this.isowner(activity, user);

        WActivity current = activity;

        this.activateflow(activity.instance().id());

        this.setActivityState(activity.id(), -2);

        /*当前实例处在内部流转环节,主办环节取回*/
        if (activity.instance().ininner() && (activity.istep().inner() > 0) &&
                (current.istep().inner() == 0)) {
            /*全部取回*/
            if (activity.instance().iotherinnerisok(activity.istep().inner(),
                        activity.iprocess(), activity.igroup())) {
                WInner inner = null;
                inner.ihandler().converge(null, activity);

                newaid = this.createNewActivity(current.instance().id(),
                        activity.id(), current.istep().id(),
                        current.iexecutor().iuser(), current.ititle(),
                        current.iprocess(), current.igroup(), "");

                this.createExecutor(newaid, current.iexecutor().iuser(), "",
                    "", "");

                this.copyFlowObject(activity, newaid);
            }
        }
        /*当前实例处在主办流程,内部流转环节取回主办环节记录*/
        else if (!activity.instance().ininner() &&
                (activity.istep().inner() == 0) &&
                (current.istep().inner() > 0)) {
            /*内部流转最后活动记录*/
            WActivity inner4out = activity.instance().inner4out(current.istep()
                                                                       .inner(),
                    current.iprocess(), current.igroup());
            newaid = this.createNewActivity(inner4out.instance().id(),
                    activity.id(), inner4out.istep().id(),
                    inner4out.iexecutor().iuser(), inner4out.ititle(),
                    inner4out.iprocess(), inner4out.igroup(), "");

            this.createExecutor(newaid, inner4out.iexecutor().iuser(), "", "",
                "");

            this.copyFlowObject(inner4out, newaid);
        } else {
            newaid = this.createNewActivity(current.instance().id(),
                    activity.id(), current.istep().id(),
                    current.iexecutor().iuser(), current.ititle(),
                    current.iprocess(), current.igroup(), "");

            this.createExecutor(newaid, current.iexecutor().iuser(), "", "", "");

            this.copyFlowObject(activity, newaid);
        }

        return newaid;
    }

    /**
     * 取回已归档公文
     * @param activity 要取回的流程活动
     * @throws WorkflowException
     */
    public String retakefactivity(WActivity activity) throws WorkflowException {
        this.setActivityState(activity.id(), -2);

        this.activateflow(activity.instance().id());

        String newaid = this.createNewActivity(activity.instance().id(),
                activity.id(), activity.istep().id(),
                activity.iexecutor().iuser(), activity.ititle(),
                activity.iprocess(), activity.igroup(), "");

        this.createExecutor(newaid, activity.iexecutor().iuser(), "", "", "");

        this.copyFlowObject(activity, newaid);

        return newaid;
    }

    /**
     * 退回流程活动记录
     *
     * @throws WorkflowException
     */
    public void backactivity(HttpServletRequest request)
        throws WorkflowException {
        CommonBean4HSQ para = null;

        try {
            para = new CommonBean4HSQ(request);
        } catch (Exception ex) {
            throw new WorkflowException("workflowengine update error.", ex);
        }

        /*当前活动记录ID*/
        String aid = (String) para.getResource().get("aid");

        /*退回环节相关的活动记录ID*/
        String bid = (String) para.getResource().get("bid");

        /*当前办理人IP*/
        String ip = (String) para.getResource().get("eip");

        /*当前办理人hostname*/
        String hostname = (String) para.getResource().get("ehostname");

        /*当前办理人mac*/
        String mac = (String) para.getResource().get("emac");

        /*退回说明*/
        String backmemo = (String) para.getResource().get("abackmemo");

        IUser user = ISystem.getSessionUser(request);

        WInstanceManager manager = new WInstanceManager(this.conn);

        WActivity activity = manager.getActivityByID(aid);

        this.isowner(activity, user);

        WActivity back = activity.instance().iactivity(bid);

        this.setActivityState(activity.id(), -3);

        this.updateExecutor(aid, ip, hostname, mac);

        this.updateFlowObject(para, activity.instance().iflow().iobject(), aid);

        Map content = manager.getActivityContent(aid);

        activity.reloadContent(content);

        String newaid = this.createNewActivity(activity.instance().id(),
                activity.id(), back.istep().id(), back.iexecutor().iuser(),
                activity.ititle(), back.iprocess(), back.igroup(), backmemo);

        this.createExecutor(newaid, back.iexecutor().iuser(), "", "", "");

        this.copyFlowObject(activity, newaid);
    }

    /**
     * 我的待办列表
     * @param user 用户
     * @param size 待办记录
     * @return List
     */
    public List mypendinglist(IUser user, int size) {
        String sql =
            "SELECT WF_ACTIVITY.A_ID FROM WF_ACTIVITY,WF_INSTANCE,WF_EXECUTOR,WF_STEP WHERE WF_ACTIVITY.A_ID = " +
            "WF_EXECUTOR.A_ID AND WF_ACTIVITY.S_ID = WF_STEP.S_ID AND WF_STEP.S_TYPE <> 2 AND " +
            "(WF_ACTIVITY.A_STATE = 0 OR WF_ACTIVITY.A_STATE = 1 OR WF_ACTIVITY.A_STATE = -1) AND WF_EXECUTOR.USER_ID = '" +
            user.id() +
            "' AND WF_ACTIVITY.INS_ID = WF_INSTANCE.INS_ID AND WF_INSTANCE.INS_STATE = 0 ORDER BY A_STIME DESC";

        List actlist = trimmer.searchMultiData(sql, size);

        if ((actlist != null) && !actlist.isEmpty()) {
            WInstanceManager manager = new WInstanceManager(conn);

            for (int i = 0; i < actlist.size(); i++) {
                Map info = (Map) actlist.get(i);
                String number = String.valueOf(i + 1);
                String aid = (String) info.get("A_ID");

                try {
                    WActivity activity = manager.getActivityByID(aid);
                    actlist.set(i, new Object[] { number, activity });
                } catch (Exception ex) {
                    ISystem.catchException(ex);
                }
            }
        }

        return actlist;
    }

    /**
     * 我的抄送列表
     * @param user 用户
     * @param size 待办记录
     * @return List
     */
    public List mycclist(IUser user, int size) {
        /*抄送列表*/
        String sql = "SELECT A_ID FROM WF_CC WHERE OBJ_TYPE = 'u' AND OBJ_ID = '" +
            user.id() + "'";

        if (user.igroup() != null) {
            String lumeid = UserManager.iallgroupflumeid(",");

            sql += (" UNION SELECT A_ID FROM WF_CC WHERE OBJ_TYPE = 'g' AND OBJ_ID IN (" +
            lumeid + ") ORDER BY A_ID DESC");
        }

        List cclist = trimmer.searchMultiData(sql, size);

        if ((cclist != null) && !cclist.isEmpty()) {
            WInstanceManager manager = new WInstanceManager(conn);

            for (int i = 0; i < cclist.size(); i++) {
                Map info = (Map) cclist.get(i);
                String number = String.valueOf(i + 1);
                String aid = (String) info.get("A_ID");

                try {
                    WActivity activity = manager.getActivityByID(aid);

                    cclist.set(i, new Object[] { number, activity });
                } catch (Exception ex) {
                    ISystem.catchException(ex);
                }
            }
        }

        return cclist;
    }

    /**
     * 我的传阅列表
     * @param user 用户
     * @param size 待办记录
     * @return List
     */
    public List myencycliclist(IUser user, int size) {
        String sql =
            "SELECT WF_ACTIVITY.A_ID FROM WF_ACTIVITY,WF_INSTANCE,WF_EXECUTOR,WF_STEP WHERE WF_ACTIVITY.A_ID = " +
            "WF_EXECUTOR.A_ID AND WF_ACTIVITY.S_ID = WF_STEP.S_ID AND WF_STEP.S_TYPE = 2 AND WF_EXECUTOR.USER_ID = '" +
            user.id() +
            "' AND WF_ACTIVITY.INS_ID = WF_INSTANCE.INS_ID AND WF_INSTANCE.INS_STATE = 0 ORDER BY A_STIME DESC";

        List encycliclist = trimmer.searchMultiData(sql, size);

        if ((encycliclist != null) && !encycliclist.isEmpty()) {
            WInstanceManager manager = new WInstanceManager(conn);

            for (int i = 0; i < encycliclist.size(); i++) {
                Map info = (Map) encycliclist.get(i);
                String number = String.valueOf(i + 1);
                String aid = (String) info.get("A_ID");

                try {
                    WActivity activity = manager.getActivityByID(aid);

                    encycliclist.set(i, new Object[] { number, activity });
                } catch (Exception ex) {
                    ISystem.catchException(ex);
                }
            }
        }

        return encycliclist;
    }

    /**
     * 初始化工作流（多用于删除已存在的工作流测试数据）
     * @param flow 工作流
     * @param user 操作用户（必须具有admin权限）
     * @throws WorkflowException
     */
    public void reinit(WFlow flow, IUser user) throws WorkflowException {
        if (!ISystem.isAdmin(user)) {
            throw new WorkflowException("unauthorized reinit workflow.");
        }

        String sql = "SELECT * FROM WF_INSTANCE WHERE CG_ID = " + flow.id();

        List list = this.trimmer.searchMultiData(sql);

        if ((list != null) && !list.isEmpty()) {
            WInstanceManager manager = new WInstanceManager(conn);

            for (int i = 0; i < list.size(); i++) {
                Map info = (Map) list.get(i);

                String insid = (String) info.get("INS_ID");

                WInstance instance = manager.getInstanceByID(insid);

                List actList = instance.iactivitylist();

                for (int j = 0; j < actList.size(); j++) {
                    WActivity act = (WActivity) actList.get(j);

                    this.cleanActivity(act, user);
                }

                sql = "DELETE FROM WF_INSTANCE WHERE INS_ID = " + insid;

                if (!this.trimmer.execute(sql)) {
                    throw new WorkflowException("reinit workflow error.");
                }

                AnnexTool tool = new AnnexTool(conn);

                try {
                    tool.deleteAnnex(instance.isequence(), "WF_INSTANCE");
                } catch (AnnexTransactorException ex) {
                    throw new WorkflowException("reinit workflow error.", ex);
                }
            }
        }
    }

    /**
     * 活动记录是否可被取回
     *
     * @param id 活动记录ID
     * @return boolean
     */
    public boolean canRetake(String id) {
        String sql =
            "SELECT A.A_ID FROM WF_ACTIVITY A,WF_INSTANCE B WHERE A.INS_ID = B.INS_ID AND A.A_TYPE = 0 AND A.A_LASTID = " +
            id + " AND (A_STATE = 1 OR A_STATE = 2)";

        return !this.trimmer.haveMoreData(sql);
    }

    /**
     * 传阅处理
     * @param ccids 传阅范围ID
     * @param ccnames 传阅范围name
     * @param cctypes 传阅范围类型
     * @param act 当前活动记录
     * @throws WorkflowException
     */
    private void handleCC(String ccids, String ccnames, String cctypes,
        WActivity act) throws WorkflowException {
        String[] ids = ccids.split(",");
        String[] names = ccnames.split(",");
        String[] types = cctypes.split(",");

        for (int i = 0; i < ids.length; i++) {
            SimpleBean4Table sbt = new SimpleBean4TableImpl("WF_CC");
            sbt.getResource().put("aid", act.id());
            sbt.getResource().put("okey",
                act.instance().iflow().iobject().ikey());
            sbt.getResource().put("oid", ids[i]);
            sbt.getResource().put("oname", names[i]);
            sbt.getResource().put("otype", types[i]);
            sbt.getResource().put("odate", DateTrimmer.getYMDHMS());
            sbt.getResource().put("ostatus", "0");

            try {
                this.bwutil.manualSave1(sbt, conn);
            } catch (Exception ex) {
                throw new WorkflowException("handle activity to cc error.", ex);
            }
        }
    }

    /**
     * 传阅处理
     * @param ccids 传阅范围ID
     * @param ccnames 传阅范围name
     * @param cctypes 传阅范围类型
     * @param act 当前活动记录
     * @throws WorkflowException
     */
    private void removeCC(WActivity act) throws WorkflowException {
        SimpleBean4Table sbt = new SimpleBean4TableImpl("WF_CC");
        sbt.getResource().put("aid", act.id());

        try {
            this.bwutil.manualDelete1(sbt, conn);
        } catch (Exception ex) {
            throw new WorkflowException("remove cc from activity error.", ex);
        }
    }

    /**
     * 清空流程活动记录
     * @param actid 活动记录ID
     * @param user 操作用户
     * @throws WorkflowException
     */
    private void cleanActivity(WActivity activity, IUser user)
        throws WorkflowException {
        StringBuffer sqlString = new StringBuffer();

        sqlString.append(";");
        sqlString.append("DELETE FROM WF_ACTIVITY WHERE A_ID = " +
            activity.id());
        sqlString.append(";");
        sqlString.append("DELETE FROM WF_EXECUTOR WHERE A_ID = " +
            activity.id());
        sqlString.append(";");
        sqlString.append("DELETE FROM WF_ACTIVITY_OBJ WHERE A_ID = " +
            activity.id());

        if (!this.trimmer.executeBatch(sqlString.toString())) {
            throw new WorkflowException("clean activity error.");
        }

        WObject obj = activity.instance().iflow().iobject();
        List list = obj.itables();

        if ((list != null) && !list.isEmpty()) {
            AnnexTool tool = new AnnexTool(conn);

            for (int i = 0; i < list.size(); i++) {
                Table table = (Table) list.get(i);

                if (table.hasPrimaryKey()) {
                    Column keycolumn = null;

                    try {
                        keycolumn = table.column(table.getPrimaryKey()[0]);
                    } catch (ColumnNotFoundException ex) {
                        throw new WorkflowException("clean activity error.", ex);
                    }

                    List contents = activity.icontent(table);

                    String sql = null;

                    if ((contents != null) && !contents.isEmpty()) {
                        for (int j = 0; j < contents.size(); j++) {
                            Map temp = (Map) contents.get(j);

                            String keyvalue = (String) temp.get(keycolumn.getName());

                            sql = "DELETE FROM " + table.getName() + " WHERE " +
                                keycolumn.getName() + " = ?";

                            DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

                            dil.set(keyvalue);

                            if (this.trimmerI.execute(sql, dil)) {
                                try {
                                    tool.deleteAnnex(keyvalue, table.getName());
                                } catch (AnnexTransactorException ex) {
                                    throw new WorkflowException("clean activity error.",
                                        ex);
                                }
                            } else {
                                throw new WorkflowException(
                                    "clean activity error.");
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 发送文件,开始流转
     * @param request
     * @throws WorkflowException
     */
    private void send2start(CommonBean4HSQ para, IUser user)
        throws WorkflowException {
        /*当前办理人IP*/
        String ip = (String) para.getResource().get("eip");

        /*当前办理人hostname*/
        String hostname = (String) para.getResource().get("ehostname");

        /*当前办理人mac*/
        String mac = (String) para.getResource().get("emac");

        /*环节ID*/
        String sid = (String) para.getResource().get("sid");

        /*活动记录标题*/
        String atitle = (String) para.getResource().get("atitle");

        /*流程类别ID*/
        String gid = (String) para.getResource().get("gid");

        /*实例序列*/
        String sequenceA = (String) para.getResource().get("insequence");

        /*下一环节ID*/
        String nextsid = (String) para.getResource().get("nextsid");

        /*下一环节办理人*/
        String nextusers = (String) para.getResource().get("nextusers");

        /*流程类别*/
        String flowtype = (String) para.getResource().get("instype");

        /*起草岗位ID*/
        String postid = (String) para.getResource().get("inscpostid");

        /*流转对象key*/
        String objkey = (String) para.getResource().get("insobject");

        WorkflowManager wfmanager = new WorkflowManager(this.conn);
        WFlow flow = wfmanager.getWFlowById(gid);

        if ((flow == null) || flow.isEmpty()) {
            throw new WorkflowException("workflowengine send error,flow[" +
                gid + "] is null.");
        }

        this.right4handle(flow.istep(sid), user);

        WObject obj = flow.iobject();

        String insid = this.createNewInstance(flow, user, sequenceA);

        String doneaid = this.createDoneActivity(insid, sid, user, atitle);

        this.createExecutor(doneaid, user, ip, hostname, mac);

        this.createFlowObject(para, obj, doneaid, null);

        this.startactivity(doneaid, sid, nextsid, nextusers, insid, atitle,
            para, obj, flow);
    }

    /**
     * 发送文件,运行流程
     * @param para
     * @throws WorkflowException
     */
    private void send2run(CommonBean4HSQ para) throws WorkflowException {
        /*活动记录ID*/
        String doneaid = (String) para.getResource().get("aid");

        /*流程类别ID*/
        String gid = (String) para.getResource().get("gid");

        /*下一环节ID*/
        String nextsid = (String) para.getResource().get("nextsid");

        /*下一环节办理人*/
        String nextusers = (String) para.getResource().get("nextusers");

        /*当前办理人IP*/
        String ip = (String) para.getResource().get("eip");

        /*当前办理人hostname*/
        String hostname = (String) para.getResource().get("ehostname");

        /*当前办理人mac*/
        String mac = (String) para.getResource().get("emac");

        WActivity activity = this.getActivityById(doneaid);

        WFlow flow = activity.instance().iflow();

        if (flow == null) {
            throw new WorkflowException("workflowengine send error,flow[" +
                gid + "] is null.");
        }

        this.updateExecutor(doneaid, ip, hostname, mac);

        WObject obj = activity.instance().iflow().iobject();

        this.updateFlowObject(para, obj, activity.id());

        this.runactivity(activity, nextsid, nextusers, para);
    }

    /**
     * 为下一环节办理人创建新流程记录
     * @param doneaid 当前活动记录ID
     * @param sid 当前环节
     * @param nextsid 下一步环节
     * @param nextusers 下一步处理人
     * @param insid 实例ID
     * @param atitle 活动记录标题
     * @param para 参数
     * @param obj 流转对象
     * @param isfree 是否为自由流转
     * @throws WorkflowException
     */
    private void startactivity(String doneaid, String sid, String nextsid,
        String nextusers, String insid, String atitle, CommonBean4HSQ para,
        WObject obj, WFlow flow) throws WorkflowException {
        String process = "0";

        String nextpostids = (String) para.getResource().get("postids");

        /*常规流转同时提交多环节办理*/
        if ((nextsid.indexOf(";") > -1)) {
            WStep crstep = flow.istep(sid);

            String[] nextsids = nextsid.split(";");
            String[] nextuserss = nextusers.split(";");

            for (int i = 0; i < nextsids.length; i++) {
                WStep ntstep = flow.istep(nextsids[i]);

                this.plugtohandle(para, obj, crstep);

                /*开始标记流转*/
                if ((crstep.inner() == 0) && (ntstep.inner() > 0)) {
                    process = StringTool.getUniqueString();
                    this.updateActivityProcess(doneaid, process);
                }

                createActivity4Executor(nextuserss[i], crstep, ntstep, process,
                    insid, doneaid, atitle, para, obj);
            }

            if (crstep.icc() == 1) {
                /*传阅处理*/
                String ccids = StringTool.checkString(para.getResource().get("ccids"));
                String ccnames = StringTool.checkString(para.getResource().get("ccnames"));
                String cctypes = StringTool.checkString(para.getResource().get("cctypes"));

                WActivity activity = this.getActivityById(doneaid);

                this.handleCC(ccids, ccnames, cctypes, activity);
            }
        } else if ((nextsid.indexOf(";") == -1)) {
            WStep crstep = flow.istep(sid);

            WStep ntstep = flow.istep(nextsid);

            this.plugtohandle(para, obj, crstep);

            /*结束操作*/
            if (ntstep.itype() == -1) {
                this.finishinstance(insid);
            } else {
                /*开始标记流转*/
                if ((crstep.inner() == 0) && (ntstep.inner() > 0)) {
                    process = StringTool.getUniqueString();
                    this.updateActivityProcess(doneaid, process);
                }

                createActivity4Executor(nextusers, crstep, ntstep, process,
                    insid, doneaid, atitle, para, obj);
            }

            if (crstep.icc() == 1) {
                /*传阅处理*/
                String ccids = StringTool.checkString(para.getResource().get("ccids"));
                String ccnames = StringTool.checkString(para.getResource().get("ccnames"));
                String cctypes = StringTool.checkString(para.getResource().get("cctypes"));

                WActivity activity = this.getActivityById(doneaid);

                this.handleCC(ccids, ccnames, cctypes, activity);
            }
        }
    }

    /**
     * 为下一步办理人创建活动记录
     * @param nextusers
     * @param crstep
     * @param ntstep
     * @param process
     * @param insid
     * @param doneaid
     * @param atitle
     * @param para
     * @param obj
     * @throws WorkflowException
     */
    private void createActivity4Executor(String nextusers, WStep crstep,
        WStep ntstep, String process, String insid, String doneaid,
        String atitle, CommonBean4HSQ para, WObject obj)
        throws WorkflowException {
        if (!nextusers.equals("")) {
            String group = "0";

            String[] userids = nextusers.split(",");

            if ((userids != null) && (userids.length > 0)) {
                WSupportUGCenter center = null;

                try {
                    center = obj.isupport().iusergroupcenter();
                    center.setConnection(conn);
                } catch (Exception ex) {
                    throw new WorkflowException("create activity executor error.",
                        ex);
                }

                for (int j = 0; j < userids.length; j++) {
                    String id = userids[j];
                    IUser nextuser = null;

                    try {
                        nextuser = center.getUserById(id);
                    } catch (Exception ex) {
                        throw new WorkflowException(
                            " create activity executor.");
                    } finally {
                        if ((center != null) && !center.datasourceIsDefault()) {
                            center.clean();
                        }
                    }

                    if ((crstep.inner() == 0) && (ntstep.inner() > 0)) {
                        group = StringTool.getUniqueString();
                    }

                    String aid = this.createNewActivity(insid, doneaid,
                            ntstep.id(), nextuser, atitle, process, group, "");

                    this.createExecutor(aid, nextuser, "", "", "");

                    this.createFlowObject(para, obj, aid, null);

                    this.sendService(atitle, aid, nextuser, obj, ntstep);
                }
            }
        }
    }

    /**
     * 为下一环节办理人创建新流程记录
     * @param activity
     * @param crstep
     * @param ntstep
     * @param nextusers
     * @param para

     * @throws WorkflowException
     */
    private void runactivity(WActivity activity, String nextsid,
        String nextusers, CommonBean4HSQ para) throws WorkflowException {
        String process = "0";

        WStep crstep = activity.istep();

        String insid = activity.instance().id();

        WObject obj = activity.instance().iflow().iobject();

        WInstanceManager imanager = new WInstanceManager(conn);

        Map content = imanager.getActivityContent(activity.id());

        activity.reloadContent(content);

        if (nextsid.indexOf(";") > -1) {
            String[] nextsids = nextsid.split(";");
            String[] nextnextuserss = nextusers.split(";");

            for (int i = 0; i < nextsids.length; i++) {
                WStep ntstep = activity.instance().iflow().istep(nextsids[i]);

                /*结束操作*/
                if (ntstep.itype() == -1) {
                    this.doneactivity(activity.id());

                    /*判断同一环节多人办理时情况*/

                    //boolean rnt = this.canGoNextActivity(crstep, activity);
                    if (true) {
                        this.plugtohandle(para, obj, crstep);
                        this.finishinstance(activity.instance().id());
                    }
                } else {
                    this.doneactivity(activity.id());

                    /*创建新流程记录*/
                    boolean rnt = true;

                    /*进入标记环节,产生新的过程ID*/
                    if ((crstep.inner() == 0) && (ntstep.inner() > 0)) {
                        process = StringTool.getUniqueString();
                        this.updateActivityProcess(activity.id(), process);
                    }
                    /*标记环节相同,使用原标记环节过程ID*/
                    else if ((crstep.inner() > 0) && (ntstep.inner() > 0) &&
                            (crstep.inner() == ntstep.inner())) {
                        process = activity.iprocess();
                    }
                    /*标记环节结束*/
                    else if ((crstep.inner() > 0) && (ntstep.inner() == 0)) {
                        if (activity.instance().iotherinnerisok(crstep.inner(),
                                    activity.iprocess(), activity.igroup())) {
                            WInner inner = null;

                            process = activity.iprocess();
                        } else {
                            rnt = false;
                        }
                    }

                    if (rnt && !nextnextuserss[i].equals("")) {
                        this.plugtohandle(para, obj, crstep);

                        createActivity5Executor(activity, nextnextuserss[i],
                            crstep, ntstep, process, insid, activity.ititle(),
                            para, obj);
                    }
                }
            }

            if (crstep.icc() == 1) {
                /*传阅处理*/
                String ccids = StringTool.checkString(para.getResource().get("ccids"));
                String ccnames = StringTool.checkString(para.getResource().get("ccnames"));
                String cctypes = StringTool.checkString(para.getResource().get("cctypes"));
                this.handleCC(ccids, ccnames, cctypes, activity);
            }
        } else {
            WStep ntstep = activity.instance().iflow().istep(nextsid);

            /*结束操作*/
            if (ntstep.itype() == -1) {
                this.doneactivity(activity.id());

                //boolean rnt = this.canGoNextActivity(crstep, activity);
                if (true) {
                    this.plugtohandle(para, obj, crstep);
                    this.finishinstance(activity.instance().id());
                }
            } else {
                this.doneactivity(activity.id());

                /*是否可以创建新流程记录*/
                boolean rnt = true;

                /*判断内部流转情况*/
                if ((crstep.inner() == 0) && (ntstep.inner() > 0)) {
                    process = StringTool.getUniqueString();
                    this.updateActivityProcess(activity.id(), process);
                } else if ((crstep.inner() > 0) && (ntstep.inner() > 0) &&
                        (crstep.inner() == ntstep.inner())) {
                    process = activity.iprocess();
                } else if ((crstep.inner() > 0) && (ntstep.inner() == 0)) {
                    if (activity.instance().iotherinnerisok(crstep.inner(),
                                activity.iprocess(), activity.igroup())) {
                        WInner inner = null;

                        process = activity.iprocess();
                    } else {
                        rnt = false;
                    }
                }

                /*判断同一环节多人办理时情况*/

                //rnt = this.canGoNextActivity(crstep, activity);
                if (rnt && !nextusers.equals("")) {
                    this.plugtohandle(para, obj, crstep);
                    createActivity5Executor(activity, nextusers, crstep,
                        ntstep, process, insid, activity.ititle(), para, obj);
                }
            }

            if (crstep.icc() == 1) {
                /*传阅处理*/
                String ccids = StringTool.checkString(para.getResource().get("ccids"));
                String ccnames = StringTool.checkString(para.getResource().get("ccnames"));
                String cctypes = StringTool.checkString(para.getResource().get("cctypes"));
                this.handleCC(ccids, ccnames, cctypes, activity);
            }
        }
    }

    /**
     * 为下一步办理人创建活动记录(运行中,如果存在标记环节需注意group的处理)
     * @param nextusers
     * @param crstep
     * @param ntstep
     * @param process
     * @param insid
     * @param doneaid
     * @param atitle
     * @param para
     * @param obj
     * @throws WorkflowException
     */
    private void createActivity5Executor(WActivity activity, String nextusers,
        WStep crstep, WStep ntstep, String process, String insid,
        String atitle, CommonBean4HSQ para, WObject obj)
        throws WorkflowException {
        String[] userids = nextusers.split(",");

        if ((userids != null) && (userids.length > 0)) {
            WSupportUGCenter center = null;

            try {
                center = obj.isupport().iusergroupcenter();
                center.setConnection(conn);
            } catch (Exception ex) {
                throw new WorkflowException("create activity executor error.",
                    ex);
            }

            for (int i = 0; i < userids.length; i++) {
                String id = userids[i];
                IUser nextuser = null;

                try {
                    nextuser = center.getUserById(id);
                } catch (Exception ex) {
                    throw new WorkflowException(
                        "create activity executor error.");
                } finally {
                    if ((center != null) && !center.datasourceIsDefault()) {
                        center.clean();
                    }
                }

                String group = "0";

                if ((crstep.inner() == 0) && (ntstep.inner() > 0)) {
                    group = StringTool.getUniqueString();
                } else if ((crstep.inner() > 0) && (ntstep.inner() > 0)) {
                    group = activity.igroup();
                }

                String aid = this.createNewActivity(insid, activity.id(),
                        ntstep.id(), nextuser, atitle, process, group, "");

                this.createExecutor(aid, nextuser, "", "", "");

                this.createFlowObject(para, obj, aid, activity);

                this.sendService(atitle, aid, nextuser, obj, ntstep);
            }
        }
    }

    /**
     * 拷贝流程活动记录相关对象内容
     *
     * @param activity 流程活动记录内容
     * @param aid 活动记录ID
     * @throws WorkflowException
     */
    private void copyFlowObject(WActivity activity, String aid)
        throws WorkflowException {
        WObject obj = activity.instance().iflow().iobject();

        List tables = obj.itables();

        Map resultmap = new HashMap();

        if ((tables != null) && !tables.isEmpty()) {
            SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

            for (int i = 0; i < tables.size(); i++) {
                Table table = (Table) tables.get(i);

                Column keycolumn = null;

                try {
                    keycolumn = table.column(table.getPrimaryKey()[0]);
                } catch (ColumnNotFoundException ex) {
                    throw new WorkflowException("workflowengine copy object error.",
                        ex);
                }

                if (!table.hasPrimaryKey()) {
                    throw new WorkflowException(
                        "workflowengine copy object error,object table[" +
                        table.getName() + "] must has primary key.");
                }

                List contents = activity.icontent(table);

                if ((contents != null) && !contents.isEmpty()) {
                    for (int j = 0; j < contents.size(); j++) {
                        Map temp = (Map) contents.get(j);

                        SimpleBean sb = new SimpleBeanImpl();
                        sb.reload(temp);

                        /*清除原表主键值*/
                        sb.getResource().remove(keycolumn.getName());

                        SimpleBeanTransform.trunRight(sb, table);

                        SimpleBeanTransform.resetSimpleBean(sb, table, resultmap);

                        String keyid = null;

                        try {
                            Map info = (Map) processor.doSave(sb, table);

                            resultmap.putAll(info);

                            keyid = (String) info.get(keycolumn.getName());
                        } catch (Exception ex) {
                            throw new WorkflowException("workflowengine copy object error.",
                                ex);
                        }

                        this.createActivityObject(aid, obj.ikey(),
                            table.getName(), keyid);

                        if (table.hasAnnex()) {
                            //String[] annex = table.getAnnex();
                            String originpkid = (String) temp.get(keycolumn.getName());
                            AnnexTool tool = new AnnexTool(this.conn);

                            /*上一活动记录相关的附件*/
                            AnnexInfo[] annexInfos = tool.getAnnexs(originpkid,
                                    table.getName());

                            if ((annexInfos != null) &&
                                    (annexInfos.length > 0)) {
                                for (int m = 0; m < annexInfos.length; m++) {
                                    AnnexInfo annexInfo = annexInfos[m];
                                    annexInfo.setObjectID(keyid);

                                    try {
                                        tool.copyAnnex(annexInfo);
                                    } catch (Exception ex) {
                                        throw new WorkflowException("workflowengine copy object error.",
                                            ex);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 创建流程活动记录相关对象内容
     *
     * @param para 对象内容
     * @param obj 对象实例
     * @param aid 活动记录ID
     * @param lastact 上一活动记录
     * @throws WorkflowException
     */
    private void createFlowObject(CommonBean4HSQ para, WObject obj, String aid,
        WActivity lastact) throws WorkflowException {
        List tables = obj.itables();

        if ((tables != null) && !tables.isEmpty()) {
            SimpleBeanAnalyzer analyzer = new SimpleBeanAnalyzerWrap(para);
            SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

            Map resultmap = new HashMap();

            for (int i = 0; i < tables.size(); i++) {
                Table table = (Table) tables.get(i);
                Column keycolumn = null;

                try {
                    keycolumn = table.column(table.getPrimaryKey()[0]);
                } catch (ColumnNotFoundException ex) {
                    throw new WorkflowException("workflowengine create object error.",
                        ex);
                }

                if (!table.hasPrimaryKey()) {
                    throw new WorkflowException(
                        "workflowengine create object error,object table[" +
                        table.getName() + "] must has primary key.");
                }

                if (obj.handleTable(table) == 0) {
                    SimpleBean bean = analyzer.createSingleBean(table);

                    /*补充本次活动缺失的内容(参照上一活动内容)*/
                    if (lastact != null) {
                        /*上一活动记录相关表内容*/
                        Map content = (Map) lastact.icontent(table).get(0);

                        additionalSingleBeanContent(bean, table, content);
                    }

                    String keyid = null;

                    try {
                        /*清除原主键内容*/
                        bean.getResource().remove(keycolumn.getFormName());

                        Map info = (Map) processor.doSave(bean, table);

                        resultmap.putAll(info);

                        keyid = (String) info.get(keycolumn.getName());
                    } catch (Exception ex) {
                        throw new WorkflowException("workflowengine create object error.",
                            ex);
                    }

                    /*补充附件内容*/
                    if ((lastact != null) && (table.hasAnnex())) {
                        /*拷贝上次活动相关的全部附件*/
                        List lastActContent = lastact.icontent(table);

                        for (int j = 0; j < lastActContent.size(); j++) {
                            Map content = (Map) lastActContent.get(j);

                            //String[] annex = table.getAnnex();
                            String originpkid = (String) content.get(keycolumn.getName());
                            AnnexTool tool = new AnnexTool(this.conn);

                            /*上一活动记录相关的附件*/
                            AnnexInfo[] annexInfos = tool.getAnnexs(originpkid,
                                    table.getName());

                            if ((annexInfos != null) &&
                                    (annexInfos.length > 0)) {
                                for (int m = 0; m < annexInfos.length; m++) {
                                    AnnexInfo annexInfo = annexInfos[m];

                                    if (annexInfo != null) {
                                        annexInfo.setObjectID(keyid);

                                        try {
                                            tool.copyAnnex(annexInfo);
                                        } catch (Exception ex) {
                                            throw new WorkflowException("workflowengine create object error.",
                                                ex);
                                        }
                                    }
                                }
                            }
                        }
                    }

                    this.createActivityObject(aid, obj.ikey(), table.getName(),
                        keyid);
                } else if (obj.handleTable(table) == 1) {
                    String counterName = obj.countName(table);
                    SimpleBean bean = analyzer.createMultiBean(table,
                            counterName);

                    if (bean.getResource().containsKey(SimpleBean.KEY)) {
                        Iterator iter = ((List) (bean.getResource().get(SimpleBean.KEY))).iterator();

                        while (iter.hasNext()) {
                            SimpleBean _sBean = (SimpleBean) iter.next();

                            String orgKeyid = StringTool.checkString(_sBean.getResource()
                                                                           .get(keycolumn.getName()));

                            if (!orgKeyid.equals("")) {
                                List lastActContent = lastact.icontent(table);

                                additionalMultiBeanContent(_sBean, table,
                                    orgKeyid, keycolumn, lastActContent);
                            }

                            resetSimpleBean(_sBean, table, resultmap);

                            String keyid = null;

                            try {
                                /*清除原主键内容*/
                                _sBean.getResource().remove(keycolumn.getFormName());

                                Map info = (Map) processor.doSave(_sBean, table);
                                keyid = (String) info.get(keycolumn.getName());
                            } catch (ProcessorException ex) {
                                throw new WorkflowException("workflowengine create object error.",
                                    ex);
                            }

                            /*补充附件内容*/
                            if (!orgKeyid.equals("") && table.hasAnnex()) {
                                AnnexTool tool = new AnnexTool(this.conn);

                                /*上一活动记录相关的附件*/
                                AnnexInfo[] annexInfos = tool.getAnnexs(orgKeyid,
                                        table.getName());

                                if ((annexInfos != null) &&
                                        (annexInfos.length > 0)) {
                                    for (int m = 0; m < annexInfos.length;
                                            m++) {
                                        AnnexInfo annexInfo = annexInfos[m];

                                        if (annexInfo != null) {
                                            annexInfo.setObjectID(keyid);

                                            try {
                                                tool.copyAnnex(annexInfo);
                                            } catch (Exception ex) {
                                                throw new WorkflowException("workflowengine create object error.",
                                                    ex);
                                            }
                                        }
                                    }
                                }
                            }

                            this.createActivityObject(aid, obj.ikey(),
                                table.getName(), keyid);
                        }
                    }
                }
            }
        }
    }

    /**
     * 补充当前SimpleBean缺失的内容
     * @param bean 当前bean
     * @param table 当前table
     * @param content 上一记录相关内容
     */
    private void additionalSingleBeanContent(SimpleBean bean, Table table,
        Map content) {
        List list = table.columns();

        for (int j = 0; j < list.size(); j++) {
            Column column = (Column) list.get(j);

            if (!bean.getResource().containsKey(column.getFormName())) {
                if (!column.isAnnex() && content.containsKey(column.getName())) {
                    bean.getResource().put(column.getFormName(),
                        content.get(column.getName()));
                }
            }
        }
    }

    /**
     * 补充当前SimpleBean(多处理操作)缺失的内容
     * @param bean 当前bean
     * @param table 当前table
     * @param orgBeanId 上一记录相关内容主键
     * @param keyColumn 主键字段
     * @param contents 上一记录相关内容
     */
    private void additionalMultiBeanContent(SimpleBean bean, Table table,
        String orgBeanId, Column keyColumn, List contents) {
        Map content = null;

        /*根据主键查找到上一活动记录内容*/
        if ((contents != null) && !contents.isEmpty()) {
            for (int i = 0; i < contents.size(); i++) {
                Map temp = (Map) contents.get(i);

                if (orgBeanId.equals(temp.get(keyColumn.getName()))) {
                    content = temp;

                    break;
                }
            }
        }

        /*如果内容不为空*/
        if (content != null) {
            List list = table.columns();

            for (int j = 0; j < list.size(); j++) {
                Column column = (Column) list.get(j);

                if (!bean.getResource().containsKey(column.getFormName())) {
                    if (!column.isAnnex() &&
                            content.containsKey(column.getName())) {
                        bean.getResource().put(column.getFormName(),
                            content.get(column.getName()));
                    }
                }
            }
        }
    }

    /**
     * 更新流程记录相关对象内容
     * @param para 表单内容
     * @param obj 流转对象
     * @param aid 流程记录ID
     * @throws WorkflowException
     */
    private void updateFlowObject(CommonBean4HSQ para, WObject obj, String aid)
        throws WorkflowException {
        List tables = obj.itables();

        if ((tables != null) && !tables.isEmpty()) {
            SimpleBeanAnalyzer analyzer = new SimpleBeanAnalyzerWrap(para);
            SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

            for (int i = 0; i < tables.size(); i++) {
                Table table = (Table) tables.get(i);
                Column keycolumn = null;

                try {
                    keycolumn = table.column(table.getPrimaryKey()[0]);
                } catch (ColumnNotFoundException ex) {
                    throw new WorkflowException("workflowengine update object error.",
                        ex);
                }

                if (!table.hasPrimaryKey()) {
                    throw new WorkflowException(
                        "workflowengine update object error,object table[" +
                        table.getName() + "] must has primary key.");
                }

                if (obj.handleTable(table) == 0) {
                    SimpleBean bean = analyzer.createSingleBean(table);

                    try {
                        processor.doUpdate(bean, table);
                    } catch (Exception ex) {
                        throw new WorkflowException("workflowengine update object error.",
                            ex);
                    }
                } else if (obj.handleTable(table) == 1) {
                    String counterName = obj.countName(table);
                    SimpleBean bean = analyzer.createMultiBean(table,
                            counterName);

                    if (bean.getResource().containsKey(SimpleBean.KEY)) {
                        Iterator iter = ((List) (bean.getResource().get(SimpleBean.KEY))).iterator();

                        while (iter.hasNext()) {
                            SimpleBean _sBean = (SimpleBean) iter.next();
                            String keyid = StringTool.checkString(_sBean.getResource()
                                                                        .get(keycolumn.getFormName()));

                            if (!keyid.equals("")) {
                                try {
                                    processor.doUpdate(_sBean, table);
                                } catch (ProcessorException ex) {
                                    throw new WorkflowException("workflowengine update object error.",
                                        ex);
                                }
                            } else {
                                try {
                                    Map info = (Map) processor.doSave(_sBean,
                                            table);
                                    keyid = (String) info.get(keycolumn.getName());
                                    this.createActivityObject(aid, obj.ikey(),
                                        table.getName(), keyid);
                                } catch (ProcessorException ex) {
                                    throw new WorkflowException("workflowengine update object error.",
                                        ex);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 创建暂停的流程实例
     * @param flow 流程类别
     * @param user 办理人员
     * @throws WorkflowException
     */
    private String createStaticInstance(WFlow flow, IUser user)
        throws WorkflowException {
        TableRegisterCenter center = TableRegisterCenter.getInstance();

        if (!center.containsTable("WF_INSTANCE")) {
            throw new WorkflowException(
                "create instance error,not found table 'WF_INSTANCE' in table-center.");
        }

        IGroup group = user.igroup();

        SimpleBean bean = new SimpleBeanImpl();
        bean.getResource().put("gid", flow.id());
        bean.getResource().put("insstime", DateTrimmer.getYMDHMS());
        bean.getResource().put("insetime", "");
        bean.getResource().put("insltime", "");
        bean.getResource().put("insstate", "-1");
        bean.getResource().put("inscreatorid", user.id());
        bean.getResource().put("inscreatorname", user.iname());
        bean.getResource().put("inscunitid", (group != null) ? group.id() : "");
        bean.getResource().put("inscunitname",
            (group != null) ? group.iname() : "");

        SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

        Table table = center.findTable("WF_INSTANCE");

        String id = null;

        try {
            Map info = (Map) processor.doSave(bean, table);
            id = (String) info.get("INS_ID");
        } catch (ProcessorException ex) {
            throw new WorkflowException("create instance error.", ex);
        }

        return id;
    }

    /**
     * 创建流程实例
     * @param flow 流程类别
     * @param user 办理人员
     * @param sequence 流程唯一标识号
     * @throws WorkflowException
     */
    private String createNewInstance(WFlow flow, IUser user, String sequence)
        throws WorkflowException {
        TableRegisterCenter center = TableRegisterCenter.getInstance();

        if (!center.containsTable("WF_INSTANCE")) {
            throw new WorkflowException(
                "create instance error,not found table 'WF_INSTANCE' in table-center.");
        }

        IGroup group = user.igroup();

        SimpleBean bean = new SimpleBeanImpl();

        if (flow.itype().equals("free")) {
            bean.getResource().put("gid", "0");
        } else {
            bean.getResource().put("gid", flow.id());
        }

        bean.getResource().put("insstime", DateTrimmer.getYMDHMS());
        bean.getResource().put("insetime", "");
        bean.getResource().put("insltime", "");
        bean.getResource().put("insstate", "0");
        bean.getResource().put("inscreatorid", user.id());
        bean.getResource().put("inscreatorname", user.iname());
        bean.getResource().put("inscunitid", (group != null) ? group.id() : "");
        bean.getResource().put("inscunitname",
            (group != null) ? group.iname() : "");
        bean.getResource().put("insequence", sequence);

        bean.getResource().put("instype", flow.itype());
        bean.getResource().put("insobject", flow.iobject().ikey());

        SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

        Table table = center.findTable("WF_INSTANCE");

        String id = null;

        try {
            Map info = (Map) processor.doSave(bean, table);
            id = (String) info.get("INS_ID");
        } catch (ProcessorException ex) {
            throw new WorkflowException("create instance error.", ex);
        }

        return id;
    }

    /**
     * 生成活动记录(生成静态活动记录,状态为暂存)
     * @param insid 实例ID
     * @param sid 环节ID
     * @param user 办理人员
     * @param title 活动记录标题
     * @return String
     */
    private String createStaticActivity(String insid, String sid, IUser user,
        String title) throws WorkflowException {
        TableRegisterCenter center = TableRegisterCenter.getInstance();

        if (!center.containsTable("WF_ACTIVITY")) {
            throw new WorkflowException(
                "create activity error,not found table 'WF_ACTIVITY' in table-center.");
        }

        SimpleBean bean = new SimpleBeanImpl();
        bean.getResource().put("insid", insid);
        bean.getResource().put("atitle", title);
        bean.getResource().put("sid", sid);
        bean.getResource().put("astime", DateTrimmer.getYMDHMS());
        bean.getResource().put("aetime", "");
        bean.getResource().put("altime", "");
        bean.getResource().put("astate", "-1");
        bean.getResource().put("alock", "1");
        bean.getResource().put("alastid", "0");
        bean.getResource().put("alockid", user.id());
        bean.getResource().put("alockname", user.iname());
        bean.getResource().put("aprocess", "0");
        bean.getResource().put("agroup", "0");
        bean.getResource().put("atype", "0");

        SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

        Table table = center.findTable("WF_ACTIVITY");

        String id = null;

        try {
            Map info = (Map) processor.doSave(bean, table);
            id = (String) info.get("A_ID");
        } catch (ProcessorException ex) {
            throw new WorkflowException("create activity error.", ex);
        }

        return id;
    }

    /**
     * 创建已完成的活动记录
     * @param insid 实例ID
     * @param sid 环节ID
     * @param user 办理人员
     * @param title 活动记录标题
     * @return String
     */
    private String createDoneActivity(String insid, String sid, IUser user,
        String title) throws WorkflowException {
        TableRegisterCenter center = TableRegisterCenter.getInstance();

        if (!center.containsTable("WF_ACTIVITY")) {
            throw new WorkflowException(
                "create activity error,not found table 'WF_ACTIVITY' in table-center.");
        }

        SimpleBean bean = new SimpleBeanImpl();
        bean.getResource().put("insid", insid);
        bean.getResource().put("atitle", title);
        bean.getResource().put("sid", sid);
        bean.getResource().put("astime", DateTrimmer.getYMDHMS());
        bean.getResource().put("aetime", DateTrimmer.getYMDHMS());
        bean.getResource().put("altime", "");
        bean.getResource().put("astate", "2");
        bean.getResource().put("alock", "1");
        bean.getResource().put("alastid", "0");
        bean.getResource().put("alockid", user.id());
        bean.getResource().put("alockname", user.iname());
        bean.getResource().put("aprocess", "0");
        bean.getResource().put("agroup", "0");

        SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

        Table table = center.findTable("WF_ACTIVITY");

        String id = null;

        try {
            Map info = (Map) processor.doSave(bean, table);
            id = (String) info.get("A_ID");
        } catch (ProcessorException ex) {
            throw new WorkflowException("create activity error.", ex);
        }

        return id;
    }

    /**
     * 创建未办理的流程活动记录
     * @param insid 实例ID
     * @param lastid 父活动记录ID
     * @param sid 环节ID
     * @param user 办理人员
     * @param title 活动记录标题
     * @param process 过程
     * @param group 组
     * @param backmemo 返回说明
     * @return String
     * @throws WorkflowException
     */
    private String createNewActivity(String insid, String lastid, String sid,
        IUser user, String title, String process, String group, String backmemo)
        throws WorkflowException {
        TableRegisterCenter center = TableRegisterCenter.getInstance();

        if (!center.containsTable("WF_ACTIVITY")) {
            throw new WorkflowException(
                "create activity error,not found table 'WF_ACTIVITY' in table-center.");
        }

        SimpleBean bean = new SimpleBeanImpl();
        bean.getResource().put("insid", insid);
        bean.getResource().put("atitle", title);
        bean.getResource().put("sid", sid);
        bean.getResource().put("astime", DateTrimmer.getYMDHMS());
        bean.getResource().put("aetime", "");
        bean.getResource().put("altime", "");
        bean.getResource().put("astate", "0");
        bean.getResource().put("alock", "0");
        bean.getResource().put("alastid", lastid);
        bean.getResource().put("alockid", "");
        bean.getResource().put("alockname", "");
        bean.getResource().put("aprocess", process);
        bean.getResource().put("agroup", group);
        bean.getResource().put("abackmemo", backmemo);

        SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

        Table table = center.findTable("WF_ACTIVITY");

        String id = null;

        try {
            Map info = (Map) processor.doSave(bean, table);
            id = (String) info.get("A_ID");
        } catch (ProcessorException ex) {
            throw new WorkflowException("create activity error.", ex);
        }

        return id;
    }

    /**
     * 建立活动记录并与对象内容关联
     * @param aid 活动记录ID
     * @param objkey 对象KEY
     * @param tableName 对象关联表名称
     * @param keyvalue 表主键值
     * @throws WorkflowException
     */
    private void createActivityObject(String aid, String objkey,
        String tableName, String keyvalue) throws WorkflowException {
        TableRegisterCenter center = TableRegisterCenter.getInstance();

        if (!center.containsTable("WF_ACTIVITY_OBJ")) {
            throw new WorkflowException(
                "create activity-object error,not found table 'WF_ACTIVITY_OBJ' in table-center.");
        }

        SimpleBean bean = new SimpleBeanImpl();
        bean.getResource().put("aid", aid);
        bean.getResource().put("okey", objkey);
        bean.getResource().put("otname", tableName);
        bean.getResource().put("otkvalue", keyvalue);

        SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

        Table table = center.findTable("WF_ACTIVITY_OBJ");

        try {
            processor.doSave(bean, table);
        } catch (ProcessorException ex) {
            throw new WorkflowException("create activity-object error.", ex);
        }
    }

    /**
     * 创建活动执行人信息
     * @param aid 活动记录ID
     * @param user 执行人
     * @param ip 执行人IP
     * @param hostname 执行人HOSTNAME
     * @param mac 执行人MAC
     * @throws WorkflowException
     */
    private void createExecutor(String aid, IUser user, String ip,
        String hostname, String mac) throws WorkflowException {
        SimpleBean4Table bean = new SimpleBean4TableImpl("WF_EXECUTOR");
        bean.getResource().put("aid", aid);

        if (user != null) {
            IGroup group = user.igroup();

            bean.getResource().put("euserid", (user != null) ? user.id() : "0");
            bean.getResource().put("eusername",
                (user != null) ? user.iname() : "");
            bean.getResource().put("eunitid", (group != null) ? group.id() : "");
            bean.getResource().put("eunitname",
                (group != null) ? group.iname() : "");
        }

        bean.getResource().put("eip", ip);
        bean.getResource().put("ehostname", hostname);
        bean.getResource().put("emac", mac);

        BaseworkUtil util = new BaseworkUtil();

        try {
            util.manualSave1(bean, conn);
        } catch (ProcessorException ex) {
            throw new WorkflowException("create executor error.", ex);
        }
    }

    /**
     * 修改流程执行人信息
     * @param aid
     * @param ip
     * @param hostname
     * @param mac
     * @throws WorkflowException
     */
    private void updateExecutor(String aid, String ip, String hostname,
        String mac) throws WorkflowException {
        TableRegisterCenter center = TableRegisterCenter.getInstance();

        if (!center.containsTable("WF_EXECUTOR")) {
            throw new WorkflowException(
                "update executor error,not found table 'WF_EXECUTOR' in table-center.");
        }

        SimpleBean bean = new SimpleBeanImpl();
        bean.getResource().put("aid", aid);
        bean.getResource().put("eip", ip);
        bean.getResource().put("ehostname", hostname);
        bean.getResource().put("emac", mac);

        SimpleBeanProcessor processor = new SingleBeanProcessor(conn);

        Table table = center.findTable("WF_EXECUTOR");

        try {
            processor.doUpdate(bean, table);
        } catch (ProcessorException ex) {
            throw new WorkflowException("update executor error.", ex);
        }
    }

    /**
     * 修改活动记录过程
     * @param aid
     * @param process
     */
    private void updateActivityProcess(String aid, String process) {
        String sql = "UPDATE WF_ACTIVITY SET A_PROCESS = '" + process +
            "' WHERE A_ID = " + aid;
        this.trimmer.execute(sql);
    }

    /**
     * 修改活动记录标题
     *
     */
    private void updateActivityTitle(String aid, String atitle)
        throws WorkflowException {
        String sql = "UPDATE WF_ACTIVITY SET A_TITLE = ? WHERE A_ID = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

        dil.set(atitle);
        dil.set(aid);

        if (!this.trimmerI.execute(sql, dil)) {
            throw new WorkflowException("修改活动记录标题失败");
        }
    }

    /**
     * 锁定活动记录
     * @param aid 记录ID
     * @param user 锁定人
     */
    private void lockactivity(String aid, IUser user) {
        String sql = "SELECT A_LASTID FROM WF_ACTIVITY WHERE A_ID = " + aid;

        Map info = this.trimmer.searchSingleData(sql);

        String lastid = (String) info.get("A_LASTID");

        if (!lastid.equals("") && !lastid.equals("0")) {
            sql = "UPDATE WF_ACTIVITY SET A_LOCK = 1,A_LOCKID='" + user.id() +
                "',A_LOCKNAME='" + user.iname() + "',A_STATE=1 WHERE A_ID = " +
                aid;

            this.trimmer.execute(sql);
        }
    }

    /**
     * 完成流程活动
     * @param aid
     */
    private void doneactivity(String aid) {
        String sql = "UPDATE WF_ACTIVITY SET A_STATE = 2,A_ETIME = '" +
            DateTrimmer.getYMDHMS() + "' WHERE A_ID = " + aid;
        this.trimmer.execute(sql);
    }

    /**
     * 实例办理完成
     * @param insid
     */
    private void finishinstance(String insid) {
        String sql = "UPDATE WF_INSTANCE SET INS_STATE = 1,INS_END = '" +
            DateTrimmer.getYMDHMS() + "' WHERE INS_ID = " + insid;
        this.trimmer.execute(sql);
    }

    /**
     * 撤销实例
     * @param insid
     */
    private void cancelinstance(String insid) {
        String sql = "UPDATE WF_INSTANCE SET INS_STATE = -1,INS_END = '" +
            DateTrimmer.getYMDHMS() + "' WHERE INS_ID = " + insid;
        this.trimmer.execute(sql);
    }

    /**
     * 撤销活动记录
     * @param insid
     */
    private void cancelactivity(WActivity act) throws WorkflowException {
        String sql = "UPDATE WF_ACTIVITY SET A_STATE = -4,A_ETIME = '" +
            DateTrimmer.getYMDHMS() + "' WHERE A_ID = " + act.id();
        this.trimmer.execute(sql);

        this.cancelinstance(act.instance().id());

        WStep step = act.istep();

        CommonBean4HSQ bean = null;

        try {
            bean = new CommonBean4HSQ(null);
        } catch (Exception ex) {
            throw new WorkflowException("cancel activity error.", ex);
        }

        bean.getResource().put("ACTION", "CANCEL");

        this.plugtohandle(bean, act.instance().iflow().iobject(), step);
    }

    /**
     * 激活流程实例
     * @param insid
     */
    private void activateflow(String insid) {
        String sql = "UPDATE WF_INSTANCE SET INS_STATE = 0 WHERE INS_ID = " +
            insid;
        this.trimmer.execute(sql);
    }

    /**
     * 设置流程记录状态
     * @param aid 流程记录ID
     * @param state 流程记录状态
     */
    private void setActivityState(String aid, int state) {
        String sql = "UPDATE WF_ACTIVITY SET A_STATE = " + state +
            " WHERE A_ID = " + aid;
        this.trimmer.execute(sql);
    }

    /**
     * 是否是流程活动记录执行人
     * @param activity
     * @param user
     * @return
     * @throws WorkflowException
     */
    private void isowner(WActivity activity, IUser user)
        throws WorkflowException {
        if (!activity.iowner(user)) {
            throw new WorkflowException("activity '" + activity.id() +
                "' is personal,u are NOT owner.");
        }
    }

    /**
     * 根据记录ID得到流程活动记录实例
     * @param id 记录ID
     * @return WActivity
     * @throws WorkflowException
     */
    private WActivity getActivityById(String id) throws WorkflowException {
        WInstanceManager manager = new WInstanceManager(conn);

        WActivity activity = manager.getActivityByID(id);

        if (activity == null) {
            throw new WorkflowException("not found activity '" + id + "'.");
        }

        return activity;
    }

    /**
     * 插件处理(自动创建操作)
     * @param user 当前处理人
     * @param post 当前处理人所在岗位
     * @param param 待导入的参数数据
     * @param actid 新创建的流程活动记录ID
     * @param wobject 流转对象
     * @param step 流转环节
     * @throws WorkflowException
     */
    private void plugtohandle(IUser user, Object param, String actid,
        WObject wobject, WStep step) throws WorkflowException {
        List pluglist = step.iplug4import();

        if ((pluglist != null) && !pluglist.isEmpty()) {
            for (int i = 0; i < pluglist.size(); i++) {
                String handlerClassName = (String) pluglist.get(i);

                WPlugHandler handler = null;

                try {
                    handler = (WPlugHandler) Class.forName(handlerClassName)
                                                  .newInstance();
                } catch (Exception ex) {
                    throw new WorkflowException(
                        "plug to handle error, run class '" + handlerClassName +
                        "' error.", ex);
                }

                SimpleBean sb = new SimpleBeanImpl();
                sb.getResource().put("IUSER", user);
                sb.getResource().put("PARAM", param);
                sb.getResource().put("ACTIVITYID", actid);
                sb.getResource().put("WOBJECT", wobject);
                sb.getResource().put("ACTION", "NORMAL");

                /*初始化数据后,返回初始化数据结果{map[TABLE(数据表名称),COLUMN(主键名称),VALUE(主键值)],map[...]}*/
                List resultList = (List) handler.participate(conn, sb);

                for (int j = 0; j < resultList.size(); j++) {
                    Map result = (Map) resultList.get(j);

                    String tableName = (String) result.get("TABLE");
                    String pkColumnName = (String) result.get("COLUMN");
                    String pkvalue = (String) result.get("VALUE");

                    this.createActivityObject(actid, wobject.ikey(), tableName,
                        pkvalue);
                }
            }
        } else {
            throw new WorkflowException(
                "auto-create instance needs import-plug to initialize wobject");
        }
    }

    /**
     * 插件处理（调用环节事件(后)处理插件）
     * @param bean 待处理内容bean
     * @param obj 流转对象
     * @param step 当前步骤
     * @throws WorkflowException
     */
    private void plugtohandle(CommonBean4HSQ bean, WObject obj, WStep step)
        throws WorkflowException {
        List pluglist = step.iplug4outro();

        if ((pluglist != null) && !pluglist.isEmpty()) {
            /*活动记录ID*/
            String doneaid = StringTool.checkString(bean.getResource().get("aid"));

            if (!bean.getResource().containsKey("ACTION")) {
                bean.getResource().put("ACTION", "NORMAL");
            }

            if (!doneaid.equals("0")) {
                /*重新得到当前活动记录实例*/
                WActivity currentactivity = this.getActivityById(doneaid);
                bean.getResource().put("CURRENTACTIVITY", currentactivity);
            }

            for (int i = 0; i < pluglist.size(); i++) {
                String className = (String) pluglist.get(i);
                WPlugHandler handler = null;

                try {
                    handler = (WPlugHandler) Class.forName(className)
                                                  .newInstance();
                } catch (Exception ex) {
                    throw new WorkflowException("execute outro plug '" +
                        className + "' error.", ex);
                }

                handler.participate(conn, bean);
            }
        }
    }

    /**
     * 发送待办事项服务消息
     * @param title 标题
     * @param memo 描述
     * @param action 操作action
     * @param userid 用户id
     * @param username 用户姓名
     */
    private void sendService(String title, String aid, IUser user, WObject obj,
        WStep step) {
        /*个人工作平台服务*/
        if ("true".equals(this.service) && (user != null)) {
            String serverPath = this.schema + "://" + this.serverName + ":" +
                this.serverPort;

            String action = serverPath + context +
                "/system/flow.do?method=open&id=" + aid;

            StringBuffer sb = new StringBuffer(
                    "<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>");
            sb.append("<baseinfo>");
            sb.append("<event>");
            sb.append("<title><![CDATA[" + title + "]]></title>");
            sb.append("<level>0</level>");
            sb.append("<status>-1</status>");
            sb.append("<type>workflow</type>");
            sb.append("<typelabel>流转文件</typelabel>");
            sb.append("<memo><![CDATA[请办理文件 '" + title + "']]></memo>");
            sb.append("<action><![CDATA[" + action + "]]></action>");
            sb.append("<userid>" + user.ilogid() + "</userid>");
            sb.append("<username>" + user.iname() + "</username>");
            sb.append("</event>");
            sb.append("</baseinfo>");

            int connectionTimeout = 5000;
            int timeout = 30000;

            try {
                PostMethod post = new PostMethod(eventservice);

                post.setRequestHeader("Content-type",
                    "text/xml; charset=" + encoding);
                post.setRequestHeader("User-Agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727");

                ByteArrayRequestEntity entity = new ByteArrayRequestEntity(sb.toString()
                                                                             .getBytes(encoding));
                post.setRequestEntity(entity);

                HttpClient httpclient = new HttpClient();

                httpclient.setConnectionTimeout(connectionTimeout);
                httpclient.setTimeout(timeout);

                int result = httpclient.executeMethod(post);
                System.out.println("Response status code: " + result);
                System.out.println("Response body: ");
                System.out.println(StringTool.checkString(
                        post.getResponseBodyAsString()));
                post.releaseConnection();
            } catch (Exception ex) {
                ISystem.catchException(ex);
            } finally {
            }

            /*系统待办事宜*/
        }
    }

    /**
     * 重新设置操作Bean
     * <p>table存在外键字段时</p>
     * @param bean
     * @param table
     * @param resultmap
     */
    private void resetSimpleBean(SimpleBean bean, Table table, Map resultmap) {
        List list = table.foreignKeyColumns();

        if ((list != null) && !list.isEmpty()) {
            for (int i = 0; i < list.size(); i++) {
                Column col = (Column) list.get(i);

                if (resultmap.containsKey(col.getForeignColumn())) {
                    bean.getResource().put(col.getFormName(),
                        resultmap.get(col.getForeignColumn()));
                }
            }
        }
    }

    /**
     * 是否可以发起下一流程(主要判断当前环节为多人办理并且多人同时办理完成才能通过的情况)
     * @param crstep 当前环节
     * @param activity 当前流程活动记录
     * @return boolean
     */
    private boolean canGoNextActivity1(WStep crstep, WActivity activity) {
        boolean pass = false;

        /*多人同时办理并且一人以上同时办理结束后方通过*/
        if ((crstep.ipara() == 1) && (crstep.iparavalue() > 1)) {
            List childList = activity.instance().iactivitylist4mychildren(activity.ilast()
                                                                                  .id());

            int countHasFinish = 0;

            for (int k = 0; k < childList.size(); k++) {
                WActivity act = (WActivity) childList.get(k);

                if ((act.itype() == 0) && (act.istate() == 2)) {
                    countHasFinish++;

                    /*认为当前操作已经办理完成(数据库状态值已经更新,但还没有反应到当前实例中),故手工将计数器+1*/
                    if ((countHasFinish + 1) >= crstep.iparavalue()) {
                        pass = true;

                        break;
                    }
                }
            }
        } else {
            pass = true;
        }

        return pass;
    }

    /**
     * 信鸽参数map
     * @param request
     * @return Map
     */
    public static Map getPigeonparameter(HttpServletRequest request) {
        Map pigeonparameter = (Map) request.getAttribute("pigeonparameter");

        if (pigeonparameter == null) {
            pigeonparameter = new HashMap();
        }

        return pigeonparameter;
    }

    /**
     * 自动创建流程实例(返回流程实例ID)
     * @param 流程实例名称(用于在待办\已办列表中使用的标题)
     * @param param 参数数据(调用此方法前可准备必要的数据,然后传递给该方法使用)
     * @param id 流程ID
     * @param user 当前操作用户
     * @return String
     */
    public String autoCreateInstance(String title, Object param,
        String flowkey, IUser user) throws WorkflowException {
        WorkflowManager manager = new WorkflowManager(conn);
        WFlow flow = manager.getWFlowByKey(flowkey);
        WObject wobject = flow.iobject();
        WStep startStep = flow.istep4start();

        List nextSteps = startStep.itrend();

        String sequence = RandomUtil.getRandomString(10);

        String insid = this.createNewInstance(flow, user, sequence);

        String startActId = this.createNewActivity(insid, "0", startStep.id(),
                user, title, "0", "0", "");

        this.createExecutor(startActId, user, "", "", "");

        this.plugtohandle(user, param, startActId, wobject, startStep);

        return insid;
    }

    /**
     * 自动创建并运行流程实例(返回流程实例ID)
     * @param 流程实例名称(用于在待办\已办列表中使用的标题)
     * @param param 参数数据(调用此方法前可准备必要的数据,然后传递给该方法使用)
     * @param flowkey 流程唯一标识
     * @param user 当前操作用户
     * @param post 当前用户所在岗位信息
     * @return String
     */
    public String autoRunInstance(String title, Object param, String flowkey,
        IUser user) throws WorkflowException {
        WorkflowManager manager = new WorkflowManager(conn);
        WFlow flow = manager.getWFlowByKey(flowkey);
        WObject wobject = flow.iobject();
        WStep startStep = flow.istep4start();

        List nextSteps = startStep.itrend();

        /*环节办理人列表Map*/
        Map stepUserMap = new HashMap();

        /**
         * 存在下一部环节
         */
        if ((nextSteps != null) && !nextSteps.isEmpty()) {
            for (int i = 0; i < nextSteps.size(); i++) {
                WTrend trend = (WTrend) nextSteps.get(i);

                WStep step = flow.istep(trend.itrendid());

                List list = this.getStepUsers(step, user);

                if ((list == null) || list.isEmpty()) {
                    throw new WorkflowException(
                        "can't auto-run instance, next step executor is NULL.");
                }

                if ((step.ipara() == 1) && (step.iparavalue() > list.size())) {
                    throw new WorkflowException(
                        "can't auto-run instance, next step executor less than setting.");
                }

                stepUserMap.put(step.id(), list);
            }
        }

        String sequence = RandomUtil.getRandomString(10);

        String insid = this.createNewInstance(flow, user, sequence);

        String startActId = this.createDoneActivity(insid, startStep.id(),
                user, title);

        this.createExecutor(startActId, user, "", "", "");

        this.plugtohandle(user, param, startActId, wobject, startStep);

        WInstanceManager imanager = new WInstanceManager(this.conn);
        WActivity startActivity = imanager.getActivityByID(startActId);

        //List exportPlugs = startStep.iplug4export();

        /**
         * 存在下一部环节
         */
        if ((nextSteps != null) && !nextSteps.isEmpty()) {
            for (int i = 0; i < nextSteps.size(); i++) {
                WTrend trend = (WTrend) nextSteps.get(i);

                WStep step = flow.istep(trend.itrendid());

                List list = (List) stepUserMap.get(step.id());

                if (step.inner() == 0) {
                    /*下一环节单人办理*/
                    if (step.ipara() == 0) {
                        IUser nextUser = (IUser) list.get(0);
                        String newActID = this.createNewActivity(insid,
                                startActId, step.id(), nextUser, title, "0",
                                "0", "");

                        this.createExecutor(newActID, nextUser, "", "", "");

                        this.copyFlowObject(startActivity, newActID);
                    }
                    /*下一环节多人同时办理*/
                    else if (step.ipara() == 1) {
                        for (int j = 0; j < list.size(); j++) {
                            IUser nextUser = (IUser) list.get(j);
                            String newActID = this.createNewActivity(insid,
                                    startActId, step.id(), nextUser, title,
                                    "0", "0", "");

                            this.createExecutor(newActID, nextUser, "", "", "");

                            this.copyFlowObject(startActivity, newActID);
                        }
                    }
                } else {
                    for (int j = 0; j < list.size(); j++) {
                        IUser nextUser = (IUser) list.get(j);
                        String process = RandomUtil.getRandomString(10);
                        String group = RandomUtil.getRandomString(10);

                        String newActID = this.createNewActivity(insid,
                                startActId, step.id(), nextUser, title,
                                process, group, "");

                        this.createExecutor(newActID, user, "", "", "");

                        this.copyFlowObject(startActivity, newActID);

                        this.updateActivityProcess(startActId, process);
                    }
                }
            }

            //this.createNewActivity(insid, lastid, sid, user, title, process, group, backmemo)
        } else {
            throw new WorkflowException(
                "no fount next step when auto-run instance.");
        }

        return insid;
    }

    /**
     * 得到环节办理人列表
     * @param step 流程环节
     * @param user 当前用户
     * @return List
     */
    public List getStepUsers(WStep step, IUser user) {
        /*WSupport support = step.iflow().iobject().isupport();

        环节办理人列表
        List list = null;
        WSupportUGCenter supportCenter = null;

        try {
            supportCenter = support.iusergroupcenter();

            supportCenter.setConnection(this.conn);
        } catch (Exception ex) {
            ISystem.catchException(this, ex);
        } finally {
            if ((supportCenter != null) &&
                    !supportCenter.datasourceIsDefault()) {
                supportCenter.clean();
            }
        }

        return list;*/
        List list = new ArrayList();

        if ((step.irangetype() == 1) &&
                !StringTool.checkString(step.irangeids()).equals("")) {
            RoleManager rm = new RoleManager(this.conn);

            UserManager um = new UserManager(this.conn);

            GroupManager gm = new GroupManager(this.conn);

            IRole role = rm.getRoleByKey(step.irangeids());

            if (role.ireal()) {
                Object[] objs = role.iobjects();

                if ((objs != null) && (objs.length > 0)) {
                    for (int i = 0; i < objs.length; i++) {
                        String otype = (String) ((Object[]) objs[i])[0];
                        String oid = (String) ((Object[]) objs[i])[1];
                        String oname = (String) ((Object[]) objs[i])[2];

                        if (otype.equals("user")) {
                            IUser u = um.getUserById(oid);

                            if ((u != null) &&
                                    (((step.iscorr() == 1) &&
                                    GroupManager.isRace(u.igroup(),
                                        user.igroup())) ||
                                    (step.iscorr() == 0))) {
                                GroupJsonBean userNode = new GroupJsonBean4Chk();
                                userNode.setId("step_" + step.id() + "_u_" +
                                    u.id());
                                userNode.setText(u.iname());
                                userNode.setRealid(u.id());
                                userNode.setType("user");
                                userNode.setLeaf(true);
                                userNode.setParentId(step.id());
                                list.add(userNode);
                            }
                        } else if (otype.equals("group")) {
                            List users = um.getUsersInGroup(oid);

                            if ((users != null) && !users.isEmpty()) {
                                for (int j = 0; j < users.size(); j++) {
                                    IUser u = (IUser) users.get(j);

                                    if ((u != null) &&
                                            (((step.iscorr() == 1) &&
                                            GroupManager.isRace(u.igroup(),
                                                user.igroup())) ||
                                            (step.iscorr() == 0))) {
                                        GroupJsonBean userNode = new GroupJsonBean4Chk();
                                        userNode.setId("step_" + step.id() +
                                            "_u_" + u.id());
                                        userNode.setText(u.iname());
                                        userNode.setRealid(u.id());
                                        userNode.setType("user");
                                        userNode.setLeaf(true);
                                        userNode.setParentId(step.id());
                                        list.add(userNode);
                                    }
                                }
                            }
                        }
                    }
                }
            } else {
                List users = null;

                if (role.irvtype().equals("U") && (step.iscorr() == 1)) {
                    users = um.getUserByRating(user.igroup().id(),
                            role.irvrating());
                } else if (role.irvtype().equals("U") && (step.iscorr() == 0)) {
                    users = um.getUserByRating(role.irvrating());
                }

                if ((users != null) && !users.isEmpty()) {
                    for (int i = 0; i < users.size(); i++) {
                        IUser u = (IUser) users.get(i);
                        GroupJsonBean userNode = new GroupJsonBean4Chk();
                        userNode.setId("step_" + step.id() + "_u_" + u.id());
                        userNode.setText(u.iname());
                        userNode.setRealid(u.id());
                        userNode.setType("user");
                        userNode.setLeaf(true);
                        userNode.setParentId(step.id());
                        list.add(userNode);
                    }
                }
            }
        }

        return list;
    }
}
